package com.hup.minicontroller.server.service;

import android.content.Context;
import android.graphics.Point;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;

import com.hup.minicontroller.common.bluetooth.annotation.BtDataHandlerMethod;
import com.hup.minicontroller.common.bluetooth.framework.BtChannel;
import com.hup.minicontroller.common.bluetooth.handler.BtDataHandler;
import com.hup.minicontroller.common.constant.ControlActionConstant.FunctionButton;
import com.hup.minicontroller.common.framework.MainThreadHandler;
import com.hup.minicontroller.common.framework.SubThreadHandler;
import com.hup.minicontroller.common.hardware.ActionMocker;
import com.hup.minicontroller.common.model.dto.ControlConfigDto;
import com.hup.minicontroller.common.model.dto.FullScreenTouchRequest;
import com.hup.minicontroller.common.model.dto.FunctionButtonRequest;
import com.hup.minicontroller.common.model.dto.TouchPadTouchRequest;
import com.hup.minicontroller.common.netty.annotation.DataHandlerMethod;
import com.hup.minicontroller.common.netty.handler.DataHandler;
import com.hup.minicontroller.common.util.DisplayUtil;
import com.hup.minicontroller.server.ServerApplication;
import com.hup.minicontroller.server.androidService.MyAccessibilityService;
import com.hup.minicontroller.server.model.AppState;
import com.hup.minicontroller.server.model.ControlConfig;
import com.hup.minicontroller.server.model.OnlineClientSession;
import com.hup.minicontroller.server.mvp.ICursorFloaterView;
import com.hup.minicontroller.server.mvp.IMainView;

import io.netty.channel.Channel;

/**
 * 客户端消息处理类,相当于Controller
 *
 * @author hugan
 * @date 2021/5/7
 */
public class DataRequestService implements DataHandler, BtDataHandler {
    private static final String TAG = DataRequestService.class.getSimpleName();

    private final AppState appState;
    private final ControlConfig controlConfig;
    private final ActionMocker actionMocker;
    private final MainThreadHandler mainThreadHandler;
    private final TouchEventHandler touchEventHandler;

    DataRequestService(Context context, SubThreadHandler subHandler, MainThreadHandler mainThreadHandler) {
        appState = ServerApplication.getBean(MainService.class).getAppState();
        controlConfig = appState.getControlConfig();
        actionMocker = new ActionMocker(context, subHandler);
        actionMocker.setAccessibilityServiceSupplier(() -> ServerApplication.getBeanNullable(MyAccessibilityService.class));
        this.mainThreadHandler = mainThreadHandler;
        touchEventHandler = new TouchEventHandler(context);
    }

    @DataHandlerMethod
    @BtDataHandlerMethod
    public void controlConfigDto(ControlConfigDto controlConfigDto, Channel channel, BtChannel btChannel) {
        boolean notifySender = controlConfig.applyClientReq(controlConfigDto);
        //更新server界面
        ServerApplication.executeIfExist(IMainView.class, IMainView::onControlConfigChanged);
        //通知其他client
        ControlConfigDto sendToOtherClient = controlConfig.toDto();
        appState.accessClient(onlineClientSessions -> {
            for (OnlineClientSession session : onlineClientSessions) {
                boolean isSender;
                if (channel != null) {
                    isSender = session.getChannel() == channel;
                    if (isSender && !notifySender) continue;
                    session.getChannel().writeAndFlush(sendToOtherClient);
                } else {
                    isSender = session.getBtChannel() == btChannel;
                    if (isSender && !notifySender) continue;
                    session.getBtChannel().send(sendToOtherClient);
                }
            }
        });
    }

    @DataHandlerMethod
    @BtDataHandlerMethod
    public void functionButtonRequest(FunctionButtonRequest buttonRequest) {
        FunctionButton button = FunctionButton.get(buttonRequest.getButton());
        Log.i(TAG, "functionButtonRequest: " + button);
        if (!controlConfig.isEnableControl()) return;
        if (button != null) {
            if (button.runOnUiThread) {
                mainThreadHandler.post(() -> button.action.accept(actionMocker));
            } else {
                button.action.accept(actionMocker);
            }
        }
    }

    @DataHandlerMethod
    @BtDataHandlerMethod
    public void fullScreenTouchRequest(FullScreenTouchRequest fullScreenTouch) {
        touchEventHandler.handle(fullScreenTouch);
    }

    @DataHandlerMethod
    @BtDataHandlerMethod
    public void touchPadTouchRequest(TouchPadTouchRequest touchPadTouch) {
        touchEventHandler.handle(touchPadTouch);
    }

    private class TouchEventHandler {

        private final ICursorFloaterView cursorFloaterView;
        private final Display display;
        private final Point screenSize;

        /**
         * 触控板开始移动时,光标parent的屏幕坐标
         */
        private final int[] touchPadCursorParentLocationOnScreen;
        /**
         * 触控板开始移动时,光标的屏幕坐标
         */
        private final int[] touchPadCursorLocationOnScreen;

        private TouchEventHandler(Context context) {
            cursorFloaterView = ServerApplication.getBean(ICursorFloaterView.class);
            display = DisplayUtil.getDisplay(context);
            screenSize = new Point();
            touchPadCursorParentLocationOnScreen = new int[2];
            touchPadCursorLocationOnScreen = new int[2];
        }

        private void handle(FullScreenTouchRequest e) {
            if (!controlConfig.isEnableControl()) return;
            display.getRealSize(screenSize);
            int x = (int) (e.getXPercent() * screenSize.x);
            int y = (int) (e.getYPercent() * screenSize.y);
            //Log.i(TAG, "handle: action=" + e.getAction());
            switch (e.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    actionMocker.press(x, y);
                    break;
                case MotionEvent.ACTION_MOVE:
                    actionMocker.move(x, y);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    actionMocker.up(x, y);
                    break;
                default:
                    Log.e(TAG, "handle: 错误类型=" + e.getAction());
            }
            if (!controlConfig.isShowCursor()) return;
            mainThreadHandler.post(() -> cursorFloaterView.onFullScreenTouch(e.getAction(), x, y));
        }

        private void handle(TouchPadTouchRequest e) {
            if (!controlConfig.isEnableControl() || !controlConfig.isShowCursor()) return;
            switch (e.getAction()) {
                case TouchPadTouchRequest.ACTION_MOVE_START:
                    //开始移动时,记录光标位置
                    mainThreadHandler.post(() -> cursorFloaterView.onTouchPadMoveStart(touchPadCursorParentLocationOnScreen, touchPadCursorLocationOnScreen));
                    break;
                case TouchPadTouchRequest.ACTION_MOVE:
                    display.getRealSize(screenSize);
                    //光标在屏幕中的位置
                    int targetX = touchPadCursorLocationOnScreen[0] + e.getXPx();
                    if (targetX < 0) targetX = 0;
                    else if (targetX > screenSize.x - 1) targetX = screenSize.x - 1;
                    int targetY = touchPadCursorLocationOnScreen[1] + e.getYPx();
                    if (targetY < 0) targetY = 0;
                    else if (targetY > screenSize.y - 1) targetY = screenSize.y - 1;
                    actionMocker.move(targetX, targetY);
                    //光标在parent中的位置
                    int cursorXOnParent = targetX - touchPadCursorParentLocationOnScreen[0];
                    int cursorYOnParent = targetY - touchPadCursorParentLocationOnScreen[1];
                    mainThreadHandler.post(() -> cursorFloaterView.onTouchPadMove(cursorXOnParent, cursorYOnParent));
                    break;
                case TouchPadTouchRequest.ACTION_MOVE_STOP:
                    mainThreadHandler.post(cursorFloaterView::onTouchPadMoveStop);
                    break;
                case TouchPadTouchRequest.ACTION_PRESS:
                    mainThreadHandler.post(() -> {
                        cursorFloaterView.onTouchPadPress(touchPadCursorLocationOnScreen);
                        actionMocker.press(touchPadCursorLocationOnScreen[0], touchPadCursorLocationOnScreen[1]);
                    });
                    break;
                case TouchPadTouchRequest.ACTION_UP:
                    mainThreadHandler.post(() -> {
                        cursorFloaterView.onTouchPadUp(touchPadCursorLocationOnScreen);
                        actionMocker.up(touchPadCursorLocationOnScreen[0], touchPadCursorLocationOnScreen[1]);
                    });
                    break;
                case TouchPadTouchRequest.ACTION_CLICK:
                    mainThreadHandler.post(() -> {
                        cursorFloaterView.onTouchPadClick(touchPadCursorLocationOnScreen);
                        actionMocker.click(touchPadCursorLocationOnScreen[0], touchPadCursorLocationOnScreen[1]);
                    });
                    break;
            }
        }
    }

}